#include "GLCamera.h"

#define MIN(a, b) (a) < (b) ? (a) : (b)
#define MAX(a, b) (a) > (b) ? (a) : (b)

GLCamera::GLCamera(float distance, float pitch, float yaw)
    : m_distance(distance), m_pitch(pitch), m_yaw(yaw)
{
    m_worldUp = {0, 1, 0};
    UpdateCameraVectors();
}

glm::mat4 GLCamera::GetViewMatrix() const
{
    glm::mat4 view = glm::mat4(1.0f);
    glm::vec3 position = m_front * m_distance;
    view = glm::lookAt(position, {0, 0, 0}, m_up);
    return view;
}

glm::vec3 GLCamera::GetPosition() const
{
    return m_front * m_distance;
}

float GLCamera::GetDistance() const
{
    return m_distance;
}

float GLCamera::GetPitch() const
{
    return m_pitch;
}

float GLCamera::GetYaw() const
{
    return m_yaw;
}

void GLCamera::SetDistance(float d)
{
    m_distance = MAX(d, 1);
    UpdateCameraVectors();
}

void GLCamera::SetPitch(float pitch)
{
    m_pitch = MAX(-80, MIN(pitch, 80));
    UpdateCameraVectors();
}

void GLCamera::SetYaw(float yaw)
{
    m_yaw = MAX(-80, MIN(yaw, 260));
    UpdateCameraVectors();
}

void GLCamera::UpdateCameraVectors()
{
    float yaw = glm::radians(m_yaw);
    float pitch = glm::radians(m_pitch);

    // 先算出方向，然后规范化
    glm::vec3 front(cos(yaw) * cos(pitch), sin(pitch), sin(yaw) * cos(pitch));
    m_front = glm::normalize(front);

    // 然后叉乘计算另外两个方向
    m_right = glm::normalize(glm::cross(m_front, m_worldUp));
    m_up = glm::normalize(glm::cross(m_right, m_front));
}
